#!/bin/bash
#THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR THE BC1050 BLACK CARBON
# FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
#-------------------------------------------------------------
#read config file
while read line; do
eval $line
done < Config/config

#DISPLAY FILE CREATED
disp_created="0"
#THIS IS THE RELATIVE DIRECTORY VARIABLE 
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# THIS IS THE FUNCTION CALLED IN THE EVENT THAT CTRL+C IS PRESSED
cleanup ()
{
	echo "Caught Signal ... cleaning up."
	if !(rm -f Data/.locked > /dev/null); then
 		exit 1
	fi
	if [ -z ${no_plots} ]; then
		kill -9 ${plotterid}	
	fi
	echo "Done cleanup ... quitting."
	exit 1
	count=0	
}
################################################################################
#########
#                       BEGIN MAIN DISPLAY FUNCTION.                            
##########################################################################################

if [ -z $no_plots ]; then
	bash ${DIR}/plotter.sh 1>/dev/null 2>/dev/null &
	plotterid="$!"
fi
        			

#############################################################################################
# BEGIN MAIN BAM ERROR EXPANSION FUNCTION:MJV 6/17/2011
############################################################################################
expand ()
{
	#INITIALIZE THE INPUT VALUE
	input=$1
	#INITIALIZE THE RESULT
	result=''
	#INITIALIZE THE REMAINDER
	remainder='0'
	#INITIALIZE PARSED CODES
	parsedcodes=''
	#initialize the errors
	errors=''
	for i in 256 128 64 32 16 8 4 2 1; do
		remainder=`expr $input - $i`
		#echo "$input - $i = $remainder"
		if [[ $remainder -gt 0 ]]; then
			result="$result $i"
			input=$remainder  
			#echo "input is now $input" 
		elif [[ $remainder -lt 0 ]]; then
			false
			#echo $result
		elif [[ $remainder -eq 0 ]]; then
			result="$result $i"
			echo "$result"
			exit 0
		fi
	done
}
##############################################################################################
# BEGIN MAIN BAM ERROR TRANSLATION FUNCTION:MJV 6/17/2011
##############################################################################################
translate () {
	#initialize the variables
	error_string=''
	errors=''
	
	for c in $@; do
		case $c in
		256)
			errors="THE FLOW, LED T, DET, AT, OR BP AR OUTSIDE NORMAL RANGE $errors"
			;;
		128)
			errors="HIGH CONCENTRATION, $errors"
			;;		
		64)
			errors="DETECTOR FAILURE, $errors"
			;;
		32)
			errors="TAPE ADVANCE, $errors"
			;;
		16)
			errors="FLOW FAILURE, $errors"
			;;
		8)
			errors="MAINTENANCE, $errors"
			;;
		4)
			errors="TAPE MOVE FAILURE, $errors"
			;;
		2)
			errors="DIGITAL SENSOR LINK FAILURE, $errors"
			;;
		1)
			errors="POWER FAILURE, $errors"
			;;
		
		esac
	
	done	
	echo $errors | sed 's/,$//g'
}
############################################################################################
#BEGIN CORRECTED DATA FUNCTION
#THIS FUNCTION QUERIES THE BC1050 FOR THE LAST TWO TAPE CHANGES
#AND REQUESTS THE CALCULATED CORRECTED DATA.
#THE FUNCTION ALSO CREATES A MIN FILE OF CORRECTED DATA FOR DMS UPLOAD
############################################################################################
corr_data ()
{
	#query the last 144 hours of errors and scrape for TAPE ADVANCE
	errorlist=`sjinn -d $dvc_prt -b$bd_rt -s "\\r\\r\\r\\rPR 2 144\\r" -r1500 -w2`
	cor_date=`echo "$errorlist" | grep "ADVANCE" | tail -n 2 | head -n 1`
	#echo "cor_date $cor_date" ##DEBUG

	#find date of last tape change
	while IFS=, read datestamp code; do
		rawdate=$datestamp
		startdate=${datestamp//[-: ]}
		#echo "IFS Loop datestamp: $datestamp" ###DEBUG
	done <<< "$cor_date"

	#convert date to seconds, this is in GMT
	startsec=`date -d "$rawdate" +%s`
	endsec=`date +%s`
	
	#convert seconds to PST
	#subtract an hour from start seconds to ensure that first hour is grabbed
	#calculate number of days difference between tape change and current time
	startsec=`expr $startsec - 32400`
	endsec=`expr $endsec - 28800`
	datedifsec=`expr $endsec - $startsec`
	datedifday=`expr $datedifsec / 86400`

	#sjinn can only handle 36 hours of data per query.
	#to workaround limitation, query corrected in 24 hour chunks.
	day_array_pointer=0 #pointer for date array for BC1050 query
	dateday[$day_array_pointer]=`date -ud @$startsec +%Y%m%d%H%M%S`
	day_array_pointer=1
	while [ "$datedifday" -gt 0 ]; do
		startsec=`expr $startsec + 86400`
		datedifday=`expr $datedifday - 1`
		#echo "calc $day_array_pointer $startsec"
		dateday[$day_array_pointer]=`date -ud @$startsec +%Y%m%d%H%M%S`
		day_array_pointer=`expr $day_array_pointer + 1`
	done
	max_da_pointer=$day_array_pointer #max cell +1 of array

	#build raw data file
	day_array_pointer=0
	temptime=$(date +%Y%m%d%H%M%S)
	tmpfile="$DIR/bc1050_$temptime"
	corr_file="$DIR/bc_corr_$temptime"
	touch "$corr_file"
	while [ "$day_array_pointer" -lt "$max_da_pointer" ]; do
		#echo "date array pointer cell $day_array_pointer : ${dateday[$day_array_pointer]}"
		sjinn -d $dvc_prt -b$bd_rt -s "\\r\\r\\r\\rPR 1 ${dateday[day_array_pointer]}\\r" -r2391 -w4 > "$tmpfile"
		cat "$tmpfile"  | grep -v "*" | grep -v "Time" | grep -v '^$' | grep -v "\.\.\." | tail -n +4 >> "$corr_file"
		day_array_pointer=`expr $day_array_pointer + 1`
	done
	rm "$tmpfile"

	#build .MIN file
	filename_date=$(date +%m_%d_%Y_%H%M%S)
	data_file="$saroad-$filename_date.MIN"
	touch $data_file
	touch $tmpfile
	while IFS=, read tstamp eco oco ec oc sflow tflow at bp codes; do
		#echo "$tstamp"
		data_time=`date -d "$tstamp" +%m/%d/%Y\ %H:%M:%S`
		
		eco=${eco//+}
		eco=$(echo $eco | sed 's/^0*//')
		if  [ ! -z "$eco" ]; then
			echo "$saroad|EC|$data_time|0|$eco|" >> $tmpfile
		fi
		
		oco=${oco//+}
		oco=$(echo $oco | sed 's/^0*//')
		if [ ! -z "$oco" ]; then
			echo "$saroad|OC|$data_time|0|$oco|" >> $tmpfile
		fi
		
		ec=${ec//+}
		ec=$(echo $ec | sed 's/^0*//')
		if  [ ! -z "$ec" ]; then
			echo "$saroad|EC_corr|$data_time|0|$ec|" >> $tmpfile
		fi
		
		oc=${oc//+}
		oc=$(echo $oc | sed 's/^0*//')
		if [ ! -z "$oc" ]; then
			echo "$saroad|OC_corr|$data_time|0|$oc|" >> $tmpfile
		fi
		
		sflow=${sflow//+}
		sflow=$(echo $sflow | sed 's/^0*//')
		if  [ ! -z "$sflow" ]; then
			echo "$saroad|SAMFL_BC1050|$data_time|0|$sflow|" >> $tmpfile
		fi
		
		tflow=${tflow//+}
		tflow=$(echo $tflow | sed 's/^0*//')
		if  [ ! -z "$tflow" ]; then
			echo "$saroad|TOTFL_BC1050|$data_time|0|$tflow|" >> $tmpfile
		fi
		
	done < $corr_file

	sed 's/$'"/`echo \\\r`/" < $tmpfile > $data_file

	
	rm $tmpfile
	rm $corr_file
	#mv $corr_file $DIR/Data/

}
############################################################################################
#BEGIN INTERPRET_ERROR FUNCTION
#THIS FUNCTION TAKES A NUMERICAL BAM ERROR ARGUEMENT
#AND RETURNS (VIA ECHO IN DEBUG) THE ENGLISH ERRORS
#BY SETTING A VARIABLE $error_string
############################################################################################ 
interpret_error () {
	this_expansion=`expand $@` 
	error_string=`translate "$this_expansion"`
	#DEBUG
	echo $error_string
}

#BEGIN WRITE
#THIS FUNCTION HANDELS READ RIGHT HANDSHAKES BETWEEN VARIOUS DRIVERS
#IN GENERAL, THE DATA IS PLACED IN THE VARIABLE $TIMESTAMP PRIOR TO CALL
#NEXT, IT OPENS THE DATA DIRECTORY AND LOOKS FOR THE .locked FILE
#IF IT EXISTS, IT HANGS OUT UNTIL IT DOESN'T EXIST. AT THAT POINT
#IT CREATES A .locked FILE, AND APPENDS TO THE DATA RECORD.
#FINALLY IT REMOVES THE .locked FILE IT HAS CREATED.
#THIS FUNCTION ALSO PARSES THE .DISABLED FILE IN THE DRIVER FOLDER
#AND TAKES A CHANNEL OFF LINE BY PREPENDING --DISABLED-- TO EACH LINE OF CONTENT IN THE DATA DIRECTORY
#written by MJV
write()
{
	#CONFIRM THAT THERE IS NO HIDDEN FILE CALLED '.locked'
	while [ -e "Data/.locked" ]; do
			sleep .2
	done	
	echo "LOCKED" > "Data/.locked"
	
	last_data=``
	#PARSE THE .disabled File
	channel_status=`cat "${DIR}/.disabled${instance}"`
	#run display
	#display
	#IF THE FILE DOSEN'T EXIT OR IS NOT ACCESIBLE
	#MAKES SURE A VALUE OF 0 IS USED

	source sys_resources/translate_code.sh displaycode $channel_status rawcode
	
	#if [ "$error_flag" -eq "1" ]; then
	#	echo "${timestamp}${rprt_nm}${occurrence} null detected...maybe the CARBLogger was unplugged... " >> "Data/$thisalert"
	#	echo "${timestamp}${rprt_nm}${occurrence} may be disconnected EC0_${instance}=999 OC0_${instance}=999 $target_value" >> "Data/${datafile}"
	#else	
	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'$target_value'/g' | tee -a "Data/$datafile"); then
		echo "$PWD $0 GENERAL FAILURE WRITING TO RECORD: $#"
		cleanup
	fi
	#fi

	if !(rm -f "Data/.locked" > /dev/null); then
		interpret_error	echo "GENERAL FAILURE REMOVING LOCK: $#"
		exit 1
	fi
	if !(timestamp="" && data=""); then
		echo "GENERAL FAILURE CLEARING WRITE BUFFER: $#"
		cleanup
	fi	
}

#THIS IS THE ACTUAL COMMUNICATION WITH THE INSTRUMENT
#THE TIMER CONTROL. AT THE BEGINING IT TESTS FOR THE 
#EXISTENCE IF TOGGLE VARRIABLES WHICH ARE UTILIZED BOTH BY
#THE COMM ROUTINE runit() AND THE DIAGNOSTICS DATA ROUTINE
#diag()
runit()
{
	#IF THE -d, -C, or -p variable is set to on, then append those parameters
	#to the sjinn communication string. If the -i parameter is passed, diag will
	#test for IZS specific routines.
	if [ "$dtr_val" = "on" ]; then
	 	dtr="--dtr" 
	fi
	if [ "$ctr_val" = "on" ]; then
	 	ctr="--ctr"
	fi
	if [ "$p8n1_val" = "on" ]; then
	 	p8n1="-p8n1"
	fi
	#Date stamp
	today=`date "+%Y-%d-%m"`
	timestamp=$rprt_nm::`date "+%m-%d-%Y_%H:%M"`:::
	#THIS IS THE NAME OF THE DATA FILE RIGHT NOW
	datafile="$saroad-$today"

	##################################################################################################
	#
	#BEGIN BC 1050 COM ROUTINE:
	#THIS ROUTINE DESIGNED FOR CONNECTION TO "QUERY" PORT ON BAMC 1050
	#IT MUST FIRST USE <ESC>QH TO DETERMINE THE CONFIGURATION OF THE BC1050
	#AND SUBSEQUENTLY SEND A QC TO EXTRACT THE INFORMATION
	#$data=the composite of the header and the data
	#$dch=the header
	#$dcc=the data
	#NOTE THAT IN ORDER FOR THIS TO WORK HAD TO REMOVE THE DATA AND TIME STAMP SINCE THEY WERE SPACE SEPERATED,
	#AND RECOMBINE AS A SINGLE BAM_TIME ENTRY.
	##################################################################################################
	
	error_flag=0
	
	while [ "$error_flag" -lt 2 ]; do 
		data=`sjinn -d $dvc_prt -b$bd_rt -s "\\r\\r\\r\\rPR 1 2\\r" -r$rsp_lngth -w$wt_rsp1`
		data_clean=`echo "$data" | grep -v '^$' | grep -v "\.\.\." | tail -n 1 | sed 's/+//g'`
		#check to see that the error string is a valid error string - if not, transmission may be garbled
		#attempt communications up to 2x
		checkdata=`echo "${data_clean: -5}" | sed 's/[0-68]*//g'`
		if [ -z "$checkdata" ]; then
			error_flag=2
		else
			error_flag=`expr $error_flag + 1`
		fi
		
	done	

	while IFS=, read tstamp eco oco ec oc sflow tflow at bp codes; do
		#echo "$tstamp"
		log_date=`date +%m-%d-%Y_%H:%M`
		data_time=`date -d "$tstamp" +%m/%d/%Y\ %H:%M:%S`
		data_time="BC1050_TIME $tstamp"

		#eco=${eco//+}
		eco=$(echo $eco | sed 's/^0*//')
		if  [ ! -z "$ec" ]; then
			eco="ECO_1=$eco"
		fi

		#oco=${oco//+}
		oco=$(echo $oco | sed 's/^0*//')
		if [ ! -z "$oco" ]; then
			oco="OCO_1=$oco"
		fi

		sflow="SAM_FL_1=$sflow"
		tflow="TOT_FLOW_1=$tflow"
		rcodes="$codes"
		codes="ERROR_1=$codes"
		data="$eco $oco $sflow $tflow $codes $data_time"
		
	done <<< "$data_clean"
	
	#data="$eco $oco $sflow $tflow $codes $data_time"
	
	this_error=`interpret_error "$rcodes"`
	this_hour=`date '+%H'`
	if [ -n "$this_error" ] && [ "$rcodes" -ne "32" ] && [ "$rcodes" -ne "8" ]; then 
		echo `date`"${rprt_nm} has experienced:${this_error}" >> Data/errors${this_hour}  
	fi
	
	data="$data $this_error"
	
	write
}

#THIS IS THE FUNCTION RUN IN THE EVENT THAT THE REQUIRED PARAMETERS
#ARE NOT ENTERED.
usage()
{
	clear| grep -v '<esc>' 
	cat << EOF
usage: $0 options
OPTIONS:
-h	display help
-n	the device identifier
-r	rprt_nm [rn]
-d	dvc_prt [eg, /dev/ttyS0, /dev/ttyUSB1] 
-b	bd_rt [2400,4800,9600,etc.]
-c	cmnd [default is cmnd1="\h1B51480D\h\p\h1B510D\p"]
-w	wt_rsp1 [seconds]
-l	rsp_lngth [characters]
-s	SAROAD number of the station
-t	[on/off] (OPTIONAL)
-C	[on/off] (OPTIONAL)
-p	[on/off] (OPTIONAL)
-m  Minute to query the BAM on.
-I	instance
Last updated 10/3/2011
EOF
}

#HELP FUNCTION GIVES BACKGROUND ON THIS DRIVER
help_me ()
{
	clear
	cat .help
	exit 0
}
def_opts ()
{
	clear
	cat .options
}

rprt_nm= ; dvc_prt= ; bd_rt= ; cmnd1="\h1B5143480D\h\p\h1B51430D\p" ; wt_rsp1= ; bd_rt= ; rsp_lngth= ; izs_val= ;
dvc_prt= ; frqncy= ; dtr= ; ctr= ; p8n1= ; izs= ; saroad= ; p8n1= ; id_nmbr= ; factor="1000" ; 
instance=1 ; min_val=4 ;
##INITIALIZE THE BUFFER
return='NOT WRITTEN TO'
##loop through all variables and parameters
##Note that the position of the colon indicates the presence
##of a parameter to collect. The h parameter simply
##returns the help message.

while getopts “hr:m:s:d:b:c:w:l:t:C:p:I:” OPTION
do
case $OPTION in
	I)
	instance=$OPTARG
	;;
	s)
	saroad=$OPTARG
	;;
	r)
	rprt_nm=$OPTARG
	;;
	d)
	dvc_prt=$OPTARG
	;;
	b)
	bd_rt=$OPTARG
	;;
	c)
	cmnd1=$OPTARG
	;;
	w)
	wt_rsp1=$OPTARG
	;;
	l)
	rsp_lngth=$OPTARG
	;;
	t)
	dtr_val=$OPTARG
	;;
	C)
	ctr_val=$OPTARG
	;;
	p)
	p8n1_val=$OPTARG
	;;
	M)
	factor=$OPTARG
	;;
	m)
	min_val=$OPTARG
	;;
	h)
	help_me
	exit 1
	;;
	*)
	usage
	exit 1
	;;
esac
done

#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM 
#AND TESTS FOR THE RECOGNITION OF KEY WORDS IN EACH LINE OF OUTPUT.
#IF THE KEY WORD IS DETECTED ON THAT LINE, A TEST IS PERFORMED. 
#IF THE TEST SUGGESTS THAT AN ERROR CONDITION EXISTS BASED UPON THE ALLOWABLE
#RANGES SPECIFIED BY THE ARB CHECKSHEET, THE OFFENDING LINE  IS WRITTEN OUT 
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
this_name=$(cat ${DIR}/.usr$instance | grep -o "\-r [A-Za-z0-9]*" | awk '{ print $2 }')
thishour=`date "+%H"`
thisalert="errors$thishour"

##CLEAR ALL VARIABLES AND SET DEFAULTS               

#CHECK FOR THE CRITICAL PARAMETERS, IF THEY ARE NOT PRESENT THEN
#RUN THE USAGE FUNCTION WHICH RETURNS THE INSTRUCTIONS FOR PROPER USAGE
#MUST HAVE r n d b c w l i s
if [ -z "$rprt_nm" ] || [ -z "$dvc_prt" ] || [ -z "$bd_rt" ] || [ -z "$wt_rsp1" ] || [ -z "$rsp_lngth" ] || [ -z "$saroad" ] || [ -z "$min_val" ]; then
	usage
	exit
fi
#INITIALIZED THE RAN VARIABLE. THIS IS USED TO TOGGLE THE TIMER GATE
ran=0
corr_ran=0
#TRAP CTRL+C
trap cleanup 1 2 3 6 15
#SETUP THE OPERATING LOOP
while :; do
	hour=`date "+%H"`
	second=`date "+%S"`
	minute=`date "+%M"`
	if [ "$second" -eq "00" ] && [ "$ran" -eq "0" ] && [ "$minute" -eq "$min_val" ]; then
		#RUN THE RUNIT FUNCTION
		runit
		corr_data
		#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT
		#UNTIL THE BEGINNING OF THE NEXT MINUTE.
		ran=1
		#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
		#SET
		sleep 1
	else 
		#WAIT ONE SECOND
		sleep .5
		#SET RAN TO 0
		ran=0
	fi
	#if [ "$hour" -eq "00" ] || [ "$hour" -eq "12" ]; then 
	#	if [ "$corr_ran" -eq "0" ]; then
	#		corr_data
	#		corr_ran=1
	#	fi
	#else 
	#	corr_ran=0
	#fi
done
exit

